<?
Blog::$Config =& Core::$Modules['blog'];

class Blog 
{
	static $Config;	

	// генерация страниц для админки
	static public
    function admin_controller(&$Page)
	{
		//pr($Page);	
		$module_url = $Page->action->module_url;
		
		switch ($Page->action->id)
		{
			case ('posts'):
				
				// устанавливаем текущий url в качестве возвратного
				ReturnURL::set();
				
				
				// указываем id для тулабар текущей страницы
				$Page->toolbar_id = 'blog';
				// вычисляем контент - список элементов
				$limit = (int)Blog::$Config->admin_posts_per_page;
				$Page->data = Blog::get_posts("is_admin=1&parse_url=true&limit=$limit");
				
				//pr($Page->data);
				
				
				break;
				
				
			case ('edit_post'):	
				$Page->toolbar_id = 'blog';
				
				$id = (int)Core::$Request->args[0];
				$Page->data = Blog::get_post('id='.$id);
				
				// для удобства чтения отделяем теги пробелами
				$Page->data->tags = str_replace(',', ', ', $Page->data->tags);
				//pr($Page->data);
				//pr($Page);
				
				// обрабатываем данные из формы
				if (isset($_POST['data']) && is_array($_POST['data']))
				{
					
					// TODO: сделать загрузку файла ТОЛЬКО после всех проверок формы и отсутствии ошибок (либо удалять загруженные файлы при ошибках)
					// загружаем файлы из формы
					Files::upload(array(
						// размешаем загружать только картинки
						'allowed_ext' => array('jpg','gif','png'),
						));
						
						
					
					$data = (object)$_POST['data'];
					// pr($data);
					
					// обрабатываем поля с пустыми значениями + преобразуем значения формы в значения для базы данных 
					if (empty($data->show))  // галка снята
						$data->show = 0;
					if (empty($data->show_in_main))  // галка снята
						$data->show_in_main = 0;
						
					// обрабатываем файлы в форме
					
					// если дана команда удалить картинку - создаем пустое значение, которое заменит значение из базы данных
					if ( @$data->img_delete) $data->img = '';
					// pr($data);
					
					// Преобразование ДД.ММ.ГГГГ ЧЧ:ММ => Unix timestamp
					if ($unix=datetime2unix($data->datetime)) 
						$data->post_date = $unix;
					
					//pr($data);
					
					// проверяем на ошибочные значения
					if (empty($data->title) && Config('blog')->title_required)
						$Page->error .= '<div>Название не может быть пустым.</div>';
						
						
					if (empty($data->page_id))
						$Page->error .= '<div>Страница публикации не указана.</div>';
					
					// для удобства поиска в базе, перед сохранением в базу убираем пробелы между тегами + убираем множественные пробелы внутри тега
					if ($data->tags)
						$data->tags = trim(
							preg_replace(
								array('/,+\s+/', '/\s+/'), 
								array(',' , '/ /'), 
								$data->tags
							));
					
					// прибавляем данные из формы к полному набору данных
					$Page->data = (object)array_merge((array)$Page->data, (array)$data);
					//pr($Page->data);
					
					// если нет ошибок - записываем страницу в базу
					if (!$Page->error) 
					{
						$id = Blog::save_post($Page->data); 
					}
					//pr($Page->error);
					// pr($module_url.'/edit_post/'.$id, $_POST);
					
					
					// редиректим на список страниц или  возвращаемся к форме (если была нажата кнопка "сохранить и продолжить редактироание")
					if (!$Page->error) 
					{
						if (isset($_POST['save']))
							redirect($module_url.'/edit_post/'.$id);
						else
							ReturnURL::redirect($module_url);
							
					}
						
				} //end  if(!empty($_POST['page']))
				
				//$Page->data = (object)$Page->data;
				//pr($Page->data);
				
				break;
		
			case ('delete_post'):
					$id = @Core::$Request->args[0];
					
					// :TODO: здесь нужно ввести доп. защиту от неявного удаления страницы от имени администратора (через xss атаку). Напримр, выводить сначала страницу с вопросом и класть в сессию хэш, а затем удалять, только если хеш удаления верный 
					// :TODO: заменит удаление на перемещение в корзину (либо сделать модулем)
					if ($id) Blog::delete_post($id);
					ReturnURL::redirect($module_url);
				break;	
				
				
			case ('toggle_post'):
					$id = @Core::$Request->args[0];
					if ($id) Blog::toggle_post($id);
					ReturnURL::redirect($module_url);
				break;	
				
				
			case ('post_datetime'):
					$id 	= @Core::$Request->args[0];
					$datettime 	= @Core::$Request->args[1];
					if ($id && isset(Core::$Request->args[1]))
						Blog::set_datetime($id, $datettime);
					ReturnURL::redirect($module_url);
					
				break;	
				
				
			case ('settings'):
				$Page->toolbar_id = 'settings';
				
				//$module_id='blog';
				$module_id = self::$Config->id;
				
				$Page->data = @Core::$Modules[$module_id];
				//pr($Page->data);
				//pr($Page);
				
				// обрабатываем данные, переданные из формы настроек
				if (!empty($_POST['data']) && is_array($_POST['data']))
				{
					$post_data = $_POST['data'];
					
					// ... для доп. модулей - вызываем свой обрабочик ошибок 
					
					// ... для стандартных модуелй проверяем на ошибки 	
					
					// ... сохраняем данные
					// ... формируем сообщение о результате
					if (empty($Page->error))
					{
						save_array(DATA_DIR. "/settings/$module_id.php", $post_data);
						$Page->message = 'Данные успешно сохранены';
					
					}	
					
					$Page->data = (object) array_merge((array)$Page->data, $post_data);
				}
				
				
				break;	
			
		}
	}	
	
	/**
	 * get_posts($params) - извлекает из базы данных статьи блога в сответствии 
	 * с переданными параметрами
	 *
	 * @PARAM string $params  - параметры для выборки постов в формате:
	 * 						'category_id=12&limit=3&order=priority'
	 *
	 * Допустимые параметры и их значения:
	 *	limit 	- максимальное количество возвращаемых элементов (если не указано, берется из конфига модуля или 10)
	 *  start	- начальная позиция выборки, по умолчанию 0
	 *  pg 		- страница выборки, более приоритетно чем start, по умолчанию 1
	 *  order	- поле/поля для сортировки, раделенные запятыми, например: 'order=price,desc,title'. Допустимые значения в списке: имена сущесвтующих полей, а также asc и desc. Сортировка в блоге по умлчанию: 'post_date,DESC'  
	 *
	 * [имя поля]=[значение] - любое существующее имя поля будет участвовать в отборе постов. Например: 'category_id=12&title=Заголовок+статьи' В таком формате будет проверятся только тольное равенство
	 *
	 * menu_id 	- будут отобраны только те статьи, которые отображаются на страницах сайта из указного меню навигации.
	 *
	 *
	 *
	 * @RETURN array of sdtObjects - возвращает массив постов, какждый из которых - это стандартный oбъект PHP. Например, заголовок первой статьи: $posts[0]->title 
	 *
	 *  Основные свойства статьи блога: 
			id, category_id, category_title, title, urlword, 
			show, post_date  (UNIX TIMESTAMP), content, intro, 
			img (загруженная отдельно или первая картинка из поста), 
			images (массив с картинками из поста), 
	 *
	 *
	 * @EXAMPLE - пример использования:
	 * <code>	
		$posts = Blog::get_posts('category_id=2&limit=10');
		foreach ($posts as $post)
			echo "
				<h3>$post->title</h3>
				$post->content
				<hr>
			";
	 * </code>
	 *
	 *
	 */
	public static
    function get_posts($params, &$pagination=null)
    {
        // pr($params);
		
		if (!is_array($params)) parse_str($params, $params);
		
		// указываем дефолтные значения
		$params['limit_default'] = Blog::$Config->posts_per_page;
		$params['order_default'] = 'post_date,DESC';
		
		$params['menu_id'] = val($params['menu_id']); 
		$params['show_childrens'] = val($params['show_childrens']);
		
		$ids = array();// массив для id всех нужных страниц
		
		if ($params['show_childrens'])
		{
			$params['parent_page_id'] = $params['page_id']; 
			$params['page_id'] = null;
			
			$ids[]=	intval($params['parent_page_id']);
		}
		
		// вычисляем параметры для SQL запроса
		$sql_params = Core::parse_params($params, '#blog_posts', 'post_');
		// pr($params, $sql_params);
		
		
		// если нужно извлечь статьи,  опубликованные только в группе страниц из одного меню, 
		// или - статьи из дочерних страниц
		// то дорабатываем $sql_params->where
		
		if ($params['menu_id'] || $params['show_childrens'])
		{
			
			// теперь в полном списке страниц ищем те, где есть блог
			$pages_list =& Site::get_pages();
			//pr($pages_list);
			foreach($pages_list as $page)
			{
				
				// фильтруем по меню старницы
				if ($params['menu_id'] 
					&& !in_array( $params['menu_id'], $page->show_in_menu)
					)
					continue;
				
				// фильтруем по родителям страницы
				$page_parents = array($page->parent_id);
				if ($params['show_childrens'] 
					&& !in_array($params['parent_page_id'], $page_parents )
					)
					continue;
				
				// echo "$page->title <br/>";
				
				$ids[] = $page->id;
					
					
					
					
					/* 
					// если на странице присутствует виджет "лента статей", 
					//то определяем категорию этих статей из настроек виджета
					parse_str($page->widgets['blog'], $blog_params);
					if (!empty($blog_params['category_id']))
						$ids[] = $blog_params['category_id'];	
					 */	
					 
					 
					 
			}
			//pr($pages_list);
			// добавляем списко нужных катеорий в условия выборки
			$sql_params->where.=" AND (page_id IN (".implode(',', $ids).")) ";		}
			
			

		//pr(Core::$Page->pagination);
		$posts = Core::exec_sql($sql_params);
		// pr($posts);
		// pr($sql_params);
		//pr(Core::$Page->pagination);
        
		// теперь подготовим данные из базы для использования на сайте 
		$params['forsite']=1;
		
		if($posts)
		foreach ($posts as &$post)
			$post = self::prepare_post($post, $params);
		//pr($posts);
        
        return $posts;
    }
    
	
	static
	function view_post($params, $data=null)
	{
		// pr($params);
		
		// преобразуем строку с параметрами в массив
		if (!is_array($params))	parse_str($params, $params);
		
		$template = View::get_template('blog/post', $params);
		$params['forsite'] = true;
		
		// pr($template);
		
		// получаем данные для статьи
		//if (!$data) 
		$data = self::get_post('forsite=1&id='. $params['post_id'] );
		// pr($data);
		
		// фильтруем пост по указанному в параметрах id категории
		if (val($params['category_id']) 
			 && $params['category_id'] != $data->category_id
			) 
			return '';

		 
		// вычисляем код статьи
		$result = eval_template($template, $data, array('post'=>$data));
		
		//pr($result);
		return $result;
	}
	
	static
	function view_posts($params)
	{
		// преобразуем строку с параметрами в массив
		if (is_string($params)) parse_str($params, $params);
		
		// вычисляем шаблон для отображения ленты статей
		
		//
		// pr($params);
		$template = View::get_template('blog/posts', $params);
		// pr($template);
		
		
		$params['forsite'] = true;
	
	
		// получаем данные для ленты статей
		$data = self::get_posts($params, $pagination_vars);
		// pr($data);
		//pr($pagination_vars);
		
		$params['thumb_width'] = val($params['thumb_width'], self::$Config->thumb_width);
		
		// применяем шаблон и вычисляем HTML код ленты статей
		$result = eval_template($template, $data, array('params'=>$params)); //, $pagination_vars);
		
		 
		//pr($result);
		//pr($template);
		
		return $result;
	}
	

	
	
/*** Описание системы виджетов

	Виджет - это элемент содержимого, который генерируется внешним модулем.

	Виджет находиться в опредленном месте веб-страницы, и может изменять свое содержимое в зависимости от URL параметров. (Например, виджет "Лента статей" может отображать список анонсов либо полную статью в зависимости от соответствующих URL параметров).
	
	Фактически виджет - это просто вызов с параметрами некоторой функции модуля, генерирующей HTML содержимое. Виджет можно присоединять или вставлять в поле "Содержимое" в форме редактирования страницы (а в будещем, также, - в содержимое статей, глобальных блоков, и редактируемых областей в теме дизайна). Внутри содержимого виджет изображается в виде текстовой макропеременной (например [%blog:4%]), либо в виде генерируемой картинки (например <img src=/system/public/widget_thumb.php?id=4 class=widget_thumb id="[%blog:4%]" alt="Виджет 'Лента статей' №4"> ).  
	
	Алгоритм обработки виджетов в процессе генерации сайта 
	
	1. Модуль получает из базы/хранилища содержимое элемента.
	2. Если у элемента (страницы, статьи, блока и т.п) некоторые поля могут содержать виджеты, то модуль пропускает содержимое этих полей через функцию Core::parse_widgets($html)
	3. Парсер виджетов находит в контенте ссылку на виджет и извлекает его номер (например [%blog:4%] - виджет "лента статей" с набром параметров №4). Когда виджет добавляется в какое-либо поле какого-либо элемента, ему дается уникальный id, и под этим id все его параметры сохраняются в базе. Также виджет может быть добавлен (вручную) без номера, что будет означать - использовать дефолтные параметры дял виджета.
	4. Когда парсер находит в контенте виджет, он: (1)извлекает из списка зарегистрированых виджетов соответсвтующий модуль и метод, (2) извлекает из базы строку с параметрами для этого виджета, 
	4б . Возможно: парсер также извлекает параметры для виджета из URL и дефолтных настроек виджета (из конфига модуля)
	5. Парсер вызывает соответствующий Module::widget_method(widget_params);
	6. И возвращенный HTML-код вставляет вместо макропеременной виджета	
	
	
	

***/
	
	// обработчика виджета "Лента статей"
	static
	function widget_blog($params)
	{
		$params = query2array($params);
		// pr($params);
		
		if ( $post_id = intval(GET('post_id')) ) // вывод полной одной статьи 
		{
			$params['post_id']=$post_id;
			return self::view_post($params);
				
		}
		else // вывод листинга статей (список анонсов)
		{
			$params['pg']= max(1, intval(GET('pg')));
			return self::view_posts($params);
		}
		
		//return $widget_content;
	}
	
	
	static
	function widget_blog_post($params)
	{
		return self::view_post($params);
	}
	
	static
	function get_fields($table = '#blog_posts')
	{
		return Db::get_fields($table);
	}
	
	

	
	public static
    function get_category_url($cat_id)
	{
		//$page_id = Db::get_var("SELECT id FROM #site_pages WHERE modules like '%blog_category_id=$cat_id&%");
		
		
		//:TODO: в будущем нужно оптимизировать содержимое колонки #site_pages.modules - для быстрого поиска страницы с нужным модулем-виджетом (или создать отдельную таблицу)
		
		$page_id=0;
		$pages_list =& Site::get_pages();
		foreach ($pages_list as $page)
		{
			if (!empty($page->widgets['blog']))
			{
				parse_str($page->widgets['blog'], $page_blog_params);
				if (!empty($page_blog_params['category_id'])
					&& $page_blog_params['category_id'] == $cat_id
					)
					{
						$page_id = $page->id;
						break;
					}		
			}	
		}
		
		if ($page_id) 
			return Site::get_page_url($page_id);
		else
			return Core::get_url('blog','category', $cat_id);
			// return false
			
	}
	
    public static
    function get_post($params='')
    {
        parse_str($params,$params);
		if(!empty($params['id'])) 
			$where = 'id='.intval($params['id']);
		if(!empty($params['urlword'])) 
			$where = 'urlword='.Db::quote($params['urlword']);
		
		if (!empty($where))
			$post = Db::get_row('SELECT * FROM #blog_posts WHERE '.$where);
		else 
			$post = (object)array(
						'show'=>1,
						
						
					);
		//pr($post);
		
		// заменяем старый путь к картинке на новый - с поддержкой мультидоменности
		// if ($post->img)
		// {
			// $post->img = str_replace( 
				// array('^/data/',	'^'), 
				// array(DATA_URL.'/',	'' ), 
				// '^'.$post->img 
				// );
		// }
		
		
		
		$post = self::prepare_post($post, $params);
		//pr($post);
		
		return  $post; 
    }
	
	// подгатавливает необходимые свойства статьи дя сайта 
	static
	function prepare_post($post, $params='')
	{
		if (!is_array($params))  parse_str($params,$params);
		
		/* 	
			сначала подготовим свойства, 
			которые нужны и на сайте и в админке	
		*/
		
		// добавим элементы для даты и времени 
		if (empty($post->post_date)) $post->post_date = time();
		// $post->date = date('j.m.Y', $post->post_date);// 8.08.2008
		// $post->time = date('G:i', $post->post_date); //  8:08
		// $post->datetime = $post->date.' '. $post->time;
		list($post->date, $post->time, $post->datetime) = unix2datetime($post->post_date, true);
		
		// pr($post);
		
		if (!empty($post->category_id))
		{
			// добавим название категории
			$categories = self::get_categories();
			$post->category_title = $categories[$post->category_id];
			
			// сформируем URL на страницу анонсов и страницу статьи
			$post->category_url = self::get_category_url($post->category_id);
			$post->url = $post->category_url .'/?post_id='.$post->id ;
		}	/* */
		
		//pr($post);
		
		// проверяем картинку
		if(val($post->img))
		{
			
			// изменяем неработающий путь к старому хранилищу картинок,
			//   /files/...   =>   /data/files/...
			$post->img = str_replace(
						array('^/files/','^files/', '^'),
						array('/data/files/','/data/files/', ''),
						'^'.$post->img);
			// pr($pg->img);
			
			// заменяем старый путь к картинке на новый - с поддержкой мультидоменности
			// if ($post->img)
			// {
				
				// $post->img = str_replace( 
					// array('^/data/',	'^'), 
					// array(DATA_URL.'/',	'' ), 
					// '^'.$post->img 
					// );
			// }
			
			
			// если картинка существует - вычисляем её размеры и вес
			if (file_exists($file=SITE_ROOT.$post->img ))
			{
				list($post->img_width, $post->img_height) = getimagesize($file);
				$post->img_size 	= format_bytes(filesize($file));  
			}
			
		}
		$post->images = '';
		
		
		//pr($post);
		
		
		
		
		// pr(Site::get_pages());
		
		// вычисляем свойства связаной страницы публикации
		if (!empty($post->page_id))
		{
			if (empty(Site::$pages_list)) 
				$pages_list =  Site::get_pages() ;
			else 
				$pages_list =& Site::$pages_list;
			
			$page = val($pages_list[$post->page_id]);
			$post->page_title = val($page->title);
			$post->page_url = val($page->url);
			$post->page = $page;
			
			$post->url = $page->url .'/?post_id='.$post->id;
		}
		
		// pr($page);
		
		// проверяем - запрошена ли подготовка данных статьи для сайта?
		if (empty($params['forsite'])) return $post;
		
		// если файл картинки не сущесвтует - очищаем это свойство
		if (!empty($post->img) && empty($post->img_size))
			$post->img	='';
		
		
		/* 	
			теперь подготовим свойства, 
			которые нужны только на сайте 	
		*/
		
		// вычисляем анонс статьи (если анонс статьи пуст, создаем его из полного текста) 
		if (!trim(strip_tags($post->intro)))  
		{
			$intro_limit	 = intval(val($params['intro_limit']));
			if (!$intro_limit) $intro_limit = self::$Config->intro_limit;
			if (!$intro_limit) $intro_limit = 200;
							
			$post->intro = short_text($post->content, $intro_limit);
			
		}
		else
		{
			// сделать в админке настройку типа поля для Анонса  textarea / wysiwyg
			if (Config('blog')->intro_type=='textarea')
			$post->intro = nl2br($post->intro);
		}
		
		// извлекаем адреса картинок из статьи
		$post->images = extract_images($post->content);
		// pr($post->images);
		
		// извлекаем оригинальные адреса из сгенерированных миниатюр 
		foreach ( (array)$post->images AS $k => $im) 
		{
			if (strstr($im, 'thumb.php?'))
			{
				list(,$im) = explode( '?', $im);
				$im = str_replace('&amp;','&',$im);
				parse_str($im, $thumb);
				if (!empty($thumb['img']))
					$post->images[$k] = $thumb['img'];
				
			}
		}
		
			
		
		
		if(empty($post->img))
			$post->img = $post->images ? $post->images[0] : null;
		
		// pr($post->images);
		
		// Если цена - это чистое члисло без текст, то приписываем "руб"
		if ($post->price && is_numeric($post->price))
			$post->price .= " руб";
		
		// нормализуем ссылку
		if(trim($post->link))
		{
			$post->link = str_replace('http://','', trim($post->link, ' /'));
			$post->linkhttp = 'http://'.$post->link;
		}
		
		
		return $post;
	}
	

	
	static public
    function toggle_post($id)
	{
		//pr($id);
		//pr(self::get_fields());
		//pr(self::get_post("id=$id"));
		Db::query('UPDATE #blog_posts SET show = 1-show WHERE id=? ', intval($id));
		
	}
	
	
	static public
    function set_datetime($id, $datettime)
	{
		$timestamp = datetime2unix($datettime);
		//pr($timestamp);
		
		if (false!==$timestamp) 
		Db::query('UPDATE #blog_posts SET post_date = ? WHERE id=? ', $timestamp, intval($id) );
		
	}
	

    static
    function get_post_random($cat_id)
    {
        $posts = self::get_posts('limit=10&category_id='.intval($cat_id)); 
		$post  = $posts[array_rand($posts, 1)];
		return $post;
    }
    

	
    static
    function urlword2id($urlword)
    {
        
    }
    
    static
    function category_title($category_id)
    {
        
    }
    
	static $categories = array();
    
	static
    function get_categories($params=null)
    {
        if (!self::$categories)
		{
			$cats = Db::get_results("SELECT * FROM #blog_categories WHERE 1 ORDER BY title");
			foreach ($cats as $c)
				self::$categories[$c->id] = $c->title;
		}
		
		//pr(self::$categories);
		return self::$categories;
    }
    
    static
    function save_post($data)
    {
    	//pr($data);
		
		$row_id = Db::save_row('#blog_posts', $data);
		
		return $row_id;
	}
    
    static
    function delete_post($id)
    {
        $ids = array($id);
		Db::query('DELETE FROM #blog_posts WHERE id IN (?) ', $ids );
    }
	
}



